package logic;

import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.ArrayList;
import java.util.List;
import persistence.DBCommonAlter;
import persistence.DBCommonConsult;
import jpa_objects.Branch;
import jpa_objects.Business;
import jpa_objects.City;
import jpa_objects.Comment;
import jpa_objects.Discount;
import jpa_objects.Event;
import jpa_objects.Event_suggestion;
import jpa_objects.Instructor;
import jpa_objects.Player;
import jpa_objects.Review;
import jpa_objects.Sport;
import jpa_objects.Sport_calification;
import jpa_objects.User;
import json_objects_received.JaxCommonClases;
import json_objects_received.JaxPlayerClases;
import json_objects_received.JaxSport;

import json_objects_send.Basic_User;
import json_objects_send.CommonUser;
import json_objects_send.Event_Info;
import json_objects_send.Friend_request;
import json_objects_send.Full_User;
import json_objects_send.JSON_Branch;
import json_objects_send.JSON_Discount;
import json_objects_send.JSON_comment;
import json_objects_send.JSON_event_suggestion;
import json_objects_send.JSON_instructor;
import json_objects_send.JSON_review;
import json_objects_send.JSON_sport_calification;

public class CluviePlayer 
{
	public CluviePlayer()
	{

	}

	public Basic_User registerPlayer(String name, String birthday, 
			String mail, String gender, String pass, String country, String city,List<JaxSport> sports)
	{
		try{
		java.sql.Timestamp t=new java.sql.Timestamp(new java.util.Date().getTime());
		Player p=new Player("", country, "", ""+t, mail, "", name,
				0, RSA.encryptString(pass), "", "", 0, "", false, birthday, "", false, "", new City(city,country), gender);
		p.setSports_of_interest(convertJaxSportToSport(sports));
		DBCommonAlter dba=new DBCommonAlter();
		dba.saveUser(p, DBCommonAlter.SAVE_USER);
		return new Basic_User(name, mail,"",country,city,null);
		}
		catch (Exception e) {
			return null;
		}
	}

	public boolean sendEventParticipationRequest(String mail, long eventId)
	{
		DBCommonConsult dbc=new DBCommonConsult();
		Event event=dbc.getEvent(eventId);
		Player p=dbc.getPlayer(mail);
		if(p!=null)
		{
			List<Player>l=event.getApplicants();
			l.add(p);
			event.setApplicants(l);
			new DBCommonAlter().saveEvent(event,DBCommonAlter.UPDATE_EVENT);
			return true;
		}
		else
		{
			return false;
		}
	}

	public boolean sendEventSuggestion(String mailSender,String mailTo,long eventId)
	{
		DBCommonConsult dbc=new DBCommonConsult();
		Event ev=dbc.getEvent(eventId);
		Player p=dbc.getPlayer(mailTo);
		List<Event_suggestion>l=p.getEvent_suggestions();
		l.add(new Event_suggestion((""+new java.sql.Timestamp(new java.util.Date().getTime())), eventId, ev.getTitle(), mailSender));
		p.setEvent_suggestions(l);
		new DBCommonAlter().saveUser(p, DBCommonAlter.UPDATE_USER);
		return true;
	}

	public boolean sendCoachingRequest(String mailFrom,String mailTo)
	{
		DBCommonConsult dbc=new DBCommonConsult();
		Instructor ins=dbc.getInstructor(mailTo);
		List<Player>l=ins.getClient_applicants();
		l.add(dbc.getPlayer(mailFrom));
		ins.setClient_applicants(l);
		new DBCommonAlter().saveUser(ins, DBCommonAlter.UPDATE_USER);
		return true;
	}

	public boolean sendFriendRequest(String mailFrom,String mailTo)
	{
		DBCommonConsult dbc=new DBCommonConsult();
		Player first=dbc.getPlayer(mailFrom);
		Player second=dbc.getPlayer(mailTo);
		List<Player>friends=first.getFriend_applicants();
		friends.add(second);
		first.setFriend_applicants(friends);
		new DBCommonAlter().saveUser(first, DBCommonAlter.UPDATE_USER);
		return true;
	}


	public boolean accept_friend_request(String mailFrom, String mailTo)
	{
		DBCommonConsult dbc=new DBCommonConsult();
		DBCommonAlter dba = new DBCommonAlter();
		Player first=dbc.getPlayer(mailFrom);
		Player second=dbc.getPlayer(mailTo);
		List<Player>friends=first.getFriends();
		Sorter.addOrdered(friends, first);
		first.setFriends(friends);
		dba.saveUser(first, DBCommonAlter.UPDATE_USER);
		friends = second.getFriends();
		Sorter.addOrdered(friends, second);
		second.setFriends(friends);
		dba.saveUser(second, DBCommonAlter.UPDATE_USER);

		return true;
	}

	public boolean reject_friend_request(String mailFrom, String mailTo)
	{
		DBCommonConsult dbc=new DBCommonConsult();
		Player first=dbc.getPlayer(mailFrom);
		Player second=dbc.getPlayer(mailTo);
		List<Player>friends=first.getFriend_applicants();
		friends.remove(second);
		first.setFriend_applicants(friends);
		new DBCommonAlter().saveUser(first, DBCommonAlter.UPDATE_USER);
		return true;
	}

	public List<Friend_request> getFriendRequests(String mail)
	{
		DBCommonConsult dbc=new DBCommonConsult();
		Player p=dbc.getPlayer(mail);
		List<Player>l=p.getFriend_applicants();  
		List<Friend_request>requests=new ArrayList<Friend_request>();
		for (Player applicant: l)
		{
			requests.add(new Friend_request(""+new java.sql.Timestamp(new java.util.Date().getTime()),
					applicant.getMail(), mail, getFriendsInCommon(applicant.getMail(), mail)));

		}
		return requests;
	}

	public boolean setPlayerAvailable(String mail,String startDate,String endDate,
			boolean privacy,List<json_objects_received.JaxSport> sports, double lat, double lng, String country, String city)
	{
		
		DBCommonConsult dbc=new DBCommonConsult();
		Player p=dbc.getPlayer(mail);
		p.setActive(true);
		p.setStartDate(startDate);
		p.setEndDate(endDate);
		p.setPrivacy(privacy);
		p.setActive_lat(lat);
		p.setActive_lng(lng);
		p.setActive_city(new City(city, country));
		
		
		p.setActive_sports(convertJaxSportToSport(sports));
		new DBCommonAlter().saveUser(p, DBCommonAlter.UPDATE_USER);
		return true;
	}

	public boolean setPlayerUnavailable(String mail)
	{
		DBCommonConsult dbc=new DBCommonConsult();
		Player p=dbc.getPlayer(mail);
		p.setActive(false);
		p.setStartDate("");
		p.setEndDate("");
		p.setPrivacy(false);
		p.getActive_sports().clear();
		new DBCommonAlter().saveUser(p, DBCommonAlter.UPDATE_USER);
		return true;
	}

	public Full_User editPlayerProfile(String mail,String description,
			String country,String city,String picture,String phone,String carrier)
	{
		DBCommonConsult dbc=new DBCommonConsult();
		Player p=dbc.getPlayer(mail);
		p.setDescription(description);
		p.setPicture(picture);
		p.setPhone(phone);
		p.setCarrier(carrier);
		p.setCity(new City(city, country));
		new DBCommonAlter().saveUser(p, DBCommonAlter.UPDATE_USER);
		return new Full_User(country, city, 
				description, p.getJoinDate(), 
				mail, picture, p.getName(), p.getRating(), phone, p.getStatus(), 
				p.getNotifications().size(),convertBusinessToBasic(p.getFollowing_businesses()),
				convertInstructorToBasic(p.getFollowing_instructors()),
				convertEvents(p.getEvents(), mail), convertReviews(p.getReviews(), mail),
				p.getReceived().size(), carrier);
	}

	public List<JSON_instructor> getPlayerInstructors(String mail,String viewer)
	{
		DBCommonConsult dbc=new DBCommonConsult();
		List<Instructor> instructors = dbc.getPlayer(mail).getInstructors();
		List<JSON_instructor>l=new ArrayList<JSON_instructor>();
		for(Instructor ins:instructors)
		{
			l.add(new JSON_instructor(ins.getName(), sportToString(ins.getSports_of_interest()),ins.getGender(),
					ins.getInstructor_type().getType(),ins.getDiscounts().size()>0?true:false,ins.getMail(),
							getListFriendsFollowing(viewer, ins),ins.getLat1(),ins.getLng1()
							,ins.getLat2(),ins.getLng2(),ins.getLat3(),ins.getLng3()));

		}
		return l;
	}

	public List<JSON_event_suggestion> getEventSuggestions(String mail)
	{
		DBCommonConsult dbc=new DBCommonConsult();
		List<Event_suggestion>levsu=dbc.getPlayer(mail).getEvent_suggestions();
		List<JSON_event_suggestion> suggestions=new ArrayList<JSON_event_suggestion>();
		for(Event_suggestion ev: levsu)
		{
			Event e=dbc.getEvent(ev.getEvent_id());
			List<String>sports=new ArrayList<String>();
			for(Sport sp:e.getSports())
			{
				sports.add(sp.getName());
			}

			suggestions.add(new JSON_event_suggestion(sportToString(e.getSports()), ev.getDate(),
					e.getTitle(), e.getId(), ev.getMailSender(), mail, e.getOwnersName(), 
					getFriendsInCommon(e.getOwnersMail(), mail)));
		}
		return suggestions;

	}
	private List<Sport> convertJaxSportToSport(List<json_objects_received.JaxSport> sports) {
		List<Sport> r=new ArrayList<Sport>();
		for (json_objects_received.JaxSport s : sports) {
			r.add(new Sport(s.getName(),s.getWraper()));
		}
		return r;
	}
	private List<String> convertJaxSportToString(List<JaxCommonClases.JaxSport> sports) {
		// TODO Auto-generated method stub
		return null;
	}
	private List<CommonUser> getListFriendsFollowing(String viewer,
			User u) {
		List<CommonUser> r=new ArrayList<CommonUser>();
		User vie=(new DBCommonConsult()).getUser(viewer, DBCommonConsult.FOLLOW_FRIENDS);
		if((u instanceof Business || u instanceof Instructor)&& vie instanceof Player)
		{
			for (User us : ((Business) u).getFollowers()) 
			{
				int imin=0;
				List<Player> f=((Player) vie).getFriends();
				int imax=f.size()-1;
				while (imax >= imin)
				{
					/* calculate the midpoint for roughly equal partition */
					int imid = imax+imin/2;
	
					// determine which subarray to search
					if (f.get(imid).getMail().compareTo(us.getMail()) > 0 )
						// change min index to search upper subarray
						imin = imid + 1;
					else if (f.get(imid).getMail().compareTo(us.getMail()) < 0)
						// change max index to search lower subarray
						imax = imid - 1;
					else
						r.add(new CommonUser(us.getName(), us.getMail(), us.getMiniPicture(), us.getCountry(),
								us.getCity().getName()));
					
				}
			}
		}
		return r;
	}

	/**
	 * Este metodo esta duplicado con el de CluvieMain por facilidad de no crear mas instancias de las necesarias
	 * @param mail
	 * @param viewer
	 * @return
	 */
	private List<CommonUser> getFriendsInCommon(String mail,String viewer) {
		List<CommonUser> fic = new ArrayList<CommonUser>();
		if(mail.equals(viewer))
		{
			return fic;
		}
		DBCommonConsult dbc=new DBCommonConsult();

		Player a = dbc.getPlayer(mail);
		Player v = dbc.getPlayer(viewer);

		if(a !=null && v !=null)
		{
			for (Player p1 : a.getFriends()) 
			{
				int imin=0;
				List<Player> f= v.getFriends();
				int imax=f.size()-1;
				while (imax >= imin)
				{
					/* calculate the midpoint for roughly equal partition */
					int imid = imax+imin/2;

					// determine which subarray to search
					if (f.get(imid).getMail().compareTo(p1.getMail()) > 0 )
						// change min index to search upper subarray
						imin = imid + 1;
					else if (f.get(imid).getMail().compareTo(p1.getMail()) < 0)
						// change max index to search lower subarray
						imax = imid - 1;
					else
					{
						CommonUser c = new CommonUser(p1.getName(), p1.getMail(), p1.getMiniPicture(),	p1.getCountry(), p1.getCity().getName());
						fic.add(c);
					}
				}
			}
		}
		return fic;
	}


	
	private List<String> sportToString(List<Sport> active_sports) {
		List<String> r=new ArrayList<String>();
		for (Sport sport : active_sports) {
			r.add(""+sport.getName()+"/"+sport.getWraper());
		}
		return r;
	}

	private List<Basic_User> convertBusinessToBasic(
			List<Business> following_businesses) {
		List<Basic_User> r=new ArrayList<Basic_User>();
		for (Business b : following_businesses) {
			r.add(new Basic_User(b.getName(), b.getMail(), b.getMiniPicture(), b.getCountry(), 
					b.getCity().getName(), null));
		}
		return r;
	}


	private List<Basic_User> convertInstructorToBasic(
			List<Instructor> following_instructors) {
		List<Basic_User> r=new ArrayList<Basic_User>();
		for (Instructor b : following_instructors) {
			r.add(new Basic_User(b.getName(), b.getMail(), b.getMiniPicture(), b.getCountry(), b.getCity().getName(),null));
		}
		return r;
	}

	private List<Event_Info> convertEvents(List<Event> events,String viewer) {
		List<Event_Info> r=new ArrayList<Event_Info>();
		for (Event e : events) {
			r.add(new Event_Info(e.getId(), e.getAddress(), e.getDescription(), 
					e.getEnding_date(), e.getLat(), e.getLng(), e.getOpenings(),
					e.getPicture(), e.isPrivacy(), e.getStarting_date(), e.getTitle(),
					convertComments(e.getComments()), sportToString(e.getSports()),
					e.getCity().getName(), convertPlayers(e.getRegistered(), viewer),
					convertPlayers(e.getApplicants(), viewer), e.getCity().getCountry(),
					e.getOwnersMail(), e.getOwnersName(),getFriendsRegisteredInEvent(viewer,e)));
		}
		return r;
	}

	private List<Basic_User> getFriendsRegisteredInEvent(String viewer,Event e) {
		List<Basic_User> r=new ArrayList<Basic_User>();
		User u=new DBCommonConsult().getUser(viewer, DBCommonConsult.FOLLOW_FRIENDS);
		if(u instanceof Player)
		{
			for (Player us : e.getRegistered()) {
				int imin=0;
				List<Player> f= ((Player) u).getFriends();
				int imax=f.size()-1;
				while (imax >= imin)
				{
					/* calculate the midpoint for roughly equal partition */
					int imid = imax+imin/2;

					// determine which subarray to search
					if (f.get(imid).getMail().compareTo(us.getMail()) > 0 )
						// change min index to search upper subarray
						imin = imid + 1;
					else if (f.get(imid).getMail().compareTo(us.getMail()) < 0)
						// change max index to search lower subarray
						imax = imid - 1;
					else
					{
						r.add(new Basic_User(us.getName(),
								us.getMail(), us.getMiniPicture(), us.getCountry(), us.getCity().getName(),
								getFriendsInCommon(us.getMail(), viewer)));
					}
				}
			}
		}
		return r;
		
	}

	private List<Basic_User> convertPlayers(List<Player> players,String viewer) {

		List<Basic_User> r=new ArrayList<Basic_User>();
		for (Player b : players) {
			r.add(new Basic_User(b.getName(), b.getMail(), b.getMiniPicture(), b.getCountry(), b.getCity().getName()
					,getFriendsInCommon(b.getMail(), viewer)));
		}
		return r;
	}



	private List<JSON_review> convertReviews(List<Review> reviews,String viewer) {

		List<JSON_review> r=new ArrayList<JSON_review>();
		for (Review re: reviews) {
			r.add(new JSON_review(re.getMessage(), re.getDate(), re.getMailFrom(),
					re.getNameFrom(), re.getTitle(), re.getSport().getName(),
					(re.getMailFrom().equals(viewer)?true:false),re.getId()));	
		}
		return r;
	}
	private List<JSON_comment> convertComments(List<Comment> comments) {
		List<JSON_comment> r=new ArrayList<JSON_comment>();
	
		for (Comment c : comments) {
			User u=new DBCommonConsult().getUser(c.getMailFrom(), DBCommonConsult.LAZY);
			r.add(new JSON_comment(c.getDate(), c.getMailFrom(), c.getMessage(), c.getTitle(),
					u.getMiniPicture(),u.getName()));
		}
		return r;
	}

	public List<Basic_User> getSuggestedInstructors(String mail) {
		//TODO Falta modelar todo lo de que los entrenadores pueden pagar, y como pagan y su mercado objetivo y todo.
		return new ArrayList<Basic_User>();
	}

}
